package util

import (
	"encoding/json"
	"fmt"
	"github.com/iancoleman/strcase"
	"net/url"
	"reflect"
	"sort"
	"strconv"
)

func ToMapSnakeUnMap(obj interface{}, unMapFieldName []string) map[string]interface{} {
	v := reflect.ValueOf(obj)
	typeOfS := v.Type()
	m := make(map[string]interface{})
	for i := 0; i < v.NumField(); i++ {
		columnName := strcase.ToSnake(typeOfS.Field(i).Name)
		if !ArrayContains(unMapFieldName, columnName) {
			m[columnName] = v.Field(i).Interface()
		}
		fmt.Printf("Field: %s type: %s, Value: %s\n", typeOfS.Field(i).Name, typeOfS.Field(i).Type, v.Field(i).Interface())
	}
	return m
}

func ToMap(obj interface{}) map[string]interface{} {
	m := make(map[string]interface{})
	j, _ := json.Marshal(obj)
	json.Unmarshal(j, &m)
	return m
}

func StrToUrlValue(obj string) url.Values {
	params := StrToMap(obj)
	p := url.Values{}
	for k, v := range params {
		p.Add(k, GetInterfaceToString(v))
	}
	return p
}

func GetInterfaceToString(value interface{}) string {
	var key string
	if value == nil {
		return key
	}

	switch value.(type) {
	case float64:
		ft := value.(float64)
		key = strconv.FormatFloat(ft, 'f', -1, 64)
	case float32:
		ft := value.(float32)
		key = strconv.FormatFloat(float64(ft), 'f', -1, 64)
	case int:
		it := value.(int)
		key = strconv.Itoa(it)
	case uint:
		it := value.(uint)
		key = strconv.Itoa(int(it))
	case int8:
		it := value.(int8)
		key = strconv.Itoa(int(it))
	case uint8:
		it := value.(uint8)
		key = strconv.Itoa(int(it))
	case int16:
		it := value.(int16)
		key = strconv.Itoa(int(it))
	case uint16:
		it := value.(uint16)
		key = strconv.Itoa(int(it))
	case int32:
		it := value.(int32)
		key = strconv.Itoa(int(it))
	case uint32:
		it := value.(uint32)
		key = strconv.Itoa(int(it))
	case int64:
		it := value.(int64)
		key = strconv.FormatInt(it, 10)
	case uint64:
		it := value.(uint64)
		key = strconv.FormatUint(it, 10)
	case string:
		key = value.(string)
	case []byte:
		key = string(value.([]byte))
	default:
		newValue, _ := json.Marshal(value)
		key = string(newValue)
	}

	return key
}

func StrToMap(obj string) map[string]interface{} {
	m := make(map[string]interface{})
	json.Unmarshal([]byte(obj), &m)
	return m
}

func StrToMapStr(obj string) map[string]string {
	m := make(map[string]string)
	json.Unmarshal([]byte(obj), &m)
	return m
}

func ToObject(txt string, p interface{}) error {
	err := json.Unmarshal([]byte(txt), p)
	if err != nil {
		return err
	}
	return nil
}

func SortKeys(orgMap map[string]interface{}) []string {
	var keys []string
	for key := range orgMap {
		keys = append(keys, key)
	}
	sort.Strings(keys)
	return keys
}
